﻿using System.Collections.Generic;
using System;
using System.IO;
using BinarySerialization;
using System.Text;
#pragma warning disable CS0618 // Type or member is obsolete

namespace EditMode
{
    /// <summary> 
    /// F 2nd Edit savedata structure. 
    /// </summary>
    [Serializable]
    public class Edit
    {
        // ----------------------- Header ---------------------- //
        #region Header
        /// <summary> Save data file Magic. </summary> 
        [FieldOrder(0)]
        [FieldLength(4)]
        public byte[] Magic { get; set; } = new byte[4] { 0x00, 0x00, 0x00, 0x64 };

        /// <summary> First Region Value. </summary> 
        [FieldOrder(1)]
        public RegionValue RegionValue { get; set; } = RegionValue.JPN;

        /// <summary> 32bit Crc32 Checksum. </summary> 
        [FieldOrder(2)]
        public uint Crc32Checksum { get; set; }

        /// <summary> Byte lenght from 0x10 to EOF. </summary> 
        [FieldOrder(3)]
        public uint Crc32ChecksumRange { get; set; }
        #endregion
        // ----------------------- Properties ------------------ //
        #region Properties
        /// <summary> Second Region Value. </summary> 
        [FieldOrder(4)]
        public RegionValue RegionValue2 { get; set; } = RegionValue.JPN;

        /// <summary> Byte lenght from 0x10 to EOF. </summary> 
        [FieldOrder(5)]
        public uint EditDataSize { get; set; }

        /// <summary> Has to be 1576 </summary> 
        [FieldOrder(6)]
        public uint TableSize { get; set; } = 1576;

        /// <summary> BPM value, doesn't affect tempo. </summary> 
        [FieldOrder(7)]
        public float DisplayBpm { get; set; }

        /// <summary> In-game HUD-Skin. </summary> 
        [FieldOrder(8)]
        public Skins Skin { get; set; } = Skins.DEFAULT_SKIN;

        /// <summary> First Player Module. </summary> 
        [FieldOrder(9)]
        public Module Module1 { get; set; } = Module.初音ミク_オリジナル;

        /// <summary> Second Player Module. </summary> 
        [FieldOrder(10)]
        public Module Module2 { get; set; } = Module.なし;

        /// <summary> Thrid Player Module. </summary> 
        [FieldOrder(11)]
        public Module Module3 { get; set; } = Module.なし;

        /// <summary> PV slot number of song base. </summary> 
        [FieldOrder(12)]
        public ushort SongBase { get; set; } = 754;

        /// <summary> Edit difficulty measured in half star units. </summary> 
        [FieldOrder(13)]
        public byte EditDifficulty { get; set; }

        /// <summary> Unknown. </summary> 
        [FieldOrder(14)]
        [FieldLength(35)]
        public byte[] EditMisc1 { get; set; } = new byte[35];

        /// <summary> Edit end point measured in PV time units. 72000 PV time == 20:00.000 TIME. </summary> 
        [FieldOrder(15)]
        public int PvEnd { get; set; } = 72000;

        /// <summary> Player 1 Face Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(16)]
        public CustomizeItem Module1Face { get; set; } = CustomizeItem.縁なしメガネ_赤;

        /// <summary> Player 1 Head Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(17)]
        public CustomizeItem Module1Head { get; set; } = CustomizeItem.なし;

        /// <summary> Player 1 Chest Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(18)]
        public CustomizeItem Module1Chest { get; set; } = CustomizeItem.なし;

        /// <summary> Player 1 Back Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(19)]
        public CustomizeItem Module1Back { get; set; } = CustomizeItem.なし;

        /// <summary> Player 2 Face Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(20)]
        public CustomizeItem Module2Face { get; set; } = CustomizeItem.なし;

        /// <summary> Player 2 Head Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(21)]
        public CustomizeItem Module2Head { get; set; } = CustomizeItem.なし;

        /// <summary> Player 2 Chest Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(22)]
        public CustomizeItem Module2Chest { get; set; } = CustomizeItem.なし;

        /// <summary> Player 2 Back Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(23)]
        public CustomizeItem Module2Back { get; set; } = CustomizeItem.なし;

        /// <summary> Player 3 Face Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(24)]
        public CustomizeItem Module3Face { get; set; } = CustomizeItem.なし;

        /// <summary> Player 3 Head Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(25)]
        public CustomizeItem Module3Head { get; set; } = CustomizeItem.なし;

        /// <summary> Player 3 Chest Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(26)]
        public CustomizeItem Module3Chest { get; set; } = CustomizeItem.なし;

        /// <summary> Player 3 Back Accessory Slot. Different Accessory items can also be equipped here. </summary> 
        [FieldOrder(27)]
        public CustomizeItem Module3Back { get; set; } = CustomizeItem.なし;

        /// <summary> Unknown. </summary> 
        [FieldOrder(28)]
        [FieldLength(8)]
        public int[] EditMisc2 { get; set; } = new int[2] { -1, -1 };

        /// <summary> Nine digit edit password. </summary> 
        [FieldOrder(29)]
        public uint EditPassword { get; set; }

        /// <summary> Unknown. </summary> 
        [FieldOrder(30)]
        [FieldLength(24)]
        public byte[] EditMisc3 { get; set; } = new byte[24] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x4C, 0x6F, 0xC0 };

        /// <summary> Edit music file start delay value. </summary> 
        [FieldOrder(31)]
        public float SongStartTime { get; set; }

        /// <summary> Unknown. </summary> 
        [FieldOrder(32)]
        [FieldLength(38)]
        public byte[] EditMisc4 { get; set; } = new byte[38];

        [FieldOrder(33)]
        [FieldLength(38)]
        public byte[] editCreator = new byte[38];

        /// <summary> 19 character edit creator. </summary> 
        [Ignore]
        public string EditCreator
        {
            get
            {
                return Utilities.GetString(editCreator, Encoding.Unicode);
            }
            set
            {
                editCreator = Utilities.GetBytes(value, 38, Encoding.Unicode);
            }
        }

        [FieldOrder(34)]
        [FieldLength(182)]
        public byte[] audioSource = new byte[182];

        /// <summary> 91 character MP3 Audio Source. </summary> 
        [Ignore]
        public string AudioSource
        {
            get
            {
                return Utilities.GetString(audioSource, Encoding.Unicode);
            }
            set
            {
                audioSource = Utilities.GetBytes(value, 182, Encoding.Unicode);
            }
        }

        [FieldOrder(35)]
        [FieldLength(194)]
        public byte[] editComment = new byte[194];

        /// <summary> 97 character edit comment. </summary> 
        [Ignore]
        public string EditComment
        {
            get
            {
                return Utilities.GetString(editComment, Encoding.Unicode);
            }
            set
            {
                editComment = Utilities.GetBytes(value, 194, Encoding.Unicode);
            }
        }

        [FieldOrder(36)]
        [FieldLength(64)]
        public byte[] songFile = new byte[62];

        /// <summary> 31 character edit song file. </summary> 
        [Ignore]
        public string SongFile
        {
            get
            {
                return Utilities.GetString(songFile, Encoding.Unicode);
            }
            set
            {
                songFile = Utilities.GetBytes(value, 64, Encoding.Unicode);
            }
        }

        /// <summary> Button sound. 9 == なし. </summary> 
        [FieldOrder(37)]
        public byte ButtonSound { get; set; }

        /// <summary> Hold button sound. 5 == ボタンと同じ. </summary> 
        [FieldOrder(38)]
        public byte HoldSound { get; set; }

        /// <summary> Arrow button sound. 5 == ボタンと同じ. </summary> 
        [FieldOrder(39)]
        public byte ArrowSound { get; set; }

        /// <summary> Star button sound. </summary> 
        [FieldOrder(40)]
        public byte StarSound { get; set; }

        /// <summary> Double Star button sound. </summary> 
        [FieldOrder(41)]
        public byte DoubleStarSound { get; set; }

        /// <summary> Linked Star button sound. </summary> 
        [FieldOrder(42)]
        public byte LinkedSound { get; set; }

        /// <summary> Unknown. </summary> 
        [FieldOrder(43)]
        [FieldLength(140)]
        public byte[] Unknown { get; set; } = new byte[142]
        {
            0,0,0,0,1,112,118,95,55,53,52, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
            0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,
        }; // pv_754

        [FieldOrder(44)]
        [FieldLength(150)]
        public byte[] mp3Name = new byte[150];

        /// <summary> 75 character MP3 file name. </summary> 
        [Ignore]
        public string Mp3Name
        {
            get
            {
                return Utilities.GetString(mp3Name, Encoding.Unicode);
            }
            set
            {
                mp3Name = Utilities.GetBytes(value, 150, Encoding.Unicode);
            }
        }

        /// <summary> Unknown. </summary> 
        [FieldOrder(45)]
        [FieldLength(84)]
        public byte[] UnknownString { get; set; } = new byte[84];

        [FieldOrder(46)]
        [FieldLength(74)]
        public byte[] editTitle = new byte[74];

        /// <summary> 37 character edit title. </summary> 
        [Ignore]
        public string EditTitle
        {
            get
            {
                return Utilities.GetString(editTitle, Encoding.Unicode);
            }
            set
            {
                editTitle = Utilities.GetBytes(value, 74, Encoding.Unicode);
            }
        }

        /// <summary> Unknown. </summary> 
        [FieldOrder(47)]
        [FieldLength(450)]
        public byte[] UnknownEmpty { get; set; } = new byte[450];

        /// <summary> BPM changes table size. </summary> 
        [FieldOrder(48)]
        public int BpmChangesCount { get; set; }

        /// <summary> BPM changes. </summary> 
        [FieldOrder(49)]
        [FieldCount(nameof(BpmChangesCount))]
        public List<BpmChange> BPMChanges { get; set; } = new List<BpmChange>();

        /// <summary> Time signature changes table size. </summary> 
        [FieldOrder(50)]
        public int TimeSigChangesCount { get; set; }

        /// <summary> Time signature changes. </summary> 
        [FieldOrder(51)]
        [FieldCount(nameof(TimeSigChangesCount))]
        public List<TimeSigChange> TimeSigChanges { get; set; } = new List<TimeSigChange>();

        /// <summary> Timeline Markers table size. </summary> 
        [FieldOrder(52)]
        public int MarkersCount { get; set; }

        /// <summary> Timeline Markers. </summary> 
        [FieldOrder(53)]
        [FieldCount(nameof(MarkersCount))]
        public List<Marker> Markers { get; set; } = new List<Marker>();

        /// <summary> Tuplet placement areas table size. </summary> 
        [FieldOrder(54)]
        public int TupletAreasCount { get; set; }

        /// <summary> Tuplet placement areas. </summary> 
        [FieldOrder(55)]
        [FieldCount(nameof(TupletAreasCount))]
        public List<TupletArea> TupletAreas { get; set; } = new List<TupletArea>();

        /// <summary> PV base table size. </summary> 
        [FieldOrder(56)]
        public uint PvBaseTableSize { get; set; } = 0x40;

        /// <summary> PV base. </summary> 
        [FieldOrder(57)]
        [FieldLength(64)]
        public byte[] PvBaseName { get; set; } = new byte[0x40];

        /// <summary> Timeline display table size. </summary> 
        [FieldOrder(58)]
        public uint TimelineTableSize { get; set; } = 0x34;

        /// <summary> Show markers row in edit timeline. </summary> 
        [FieldOrder(59)]
        public byte TimelineMarkers { get; set; } = 0x01;

        /// <summary> Show Module 1 instructions row in edit timeline. </summary> 
        [FieldOrder(60)]
        public TimelineModule TimeLineModule1 { get; set; } = new TimelineModule();

        /// <summary> Show Module 2 instructions  row in edit timeline. </summary> 
        [FieldOrder(61)]
        public TimelineModule TimeLineModule2 { get; set; } = new TimelineModule();

        /// <summary> Show Module 3 instructions  row in edit timeline. </summary> 
        [FieldOrder(62)]
        public TimelineModule TimeLineModule3 { get; set; } = new TimelineModule();

        /// <summary> Show stages row in edit timeline. </summary> 
        [FieldOrder(63)]
        public byte TimelineSoundStage { get; set; } = 0x01;

        /// <summary> Show cameras row in edit timeline. </summary> 
        [FieldOrder(64)]
        public byte TimelineCamera { get; set; } = 0x01;

        /// <summary> Show effects row in edit timeline. </summary> 
        [FieldOrder(65)]
        public byte TimelineEffects { get; set; } = 0x01;

        /// <summary> Show fades row in edit timeline. </summary> 
        [FieldOrder(66)]
        public byte TimelineFade { get; set; } = 0x01;

        /// <summary> Show lyrics row in edit timeline. </summary> 
        [FieldOrder(67)]
        public byte TimelineLyrics { get; set; } = 0x01;

        /// <summary> Show rhythm row in edit timeline. </summary> 
        [FieldOrder(68)]
        public byte TimelineRhythm { get; set; } = 0x01;

        /// <summary> Show target row in edit timeline. </summary> 
        [FieldOrder(69)]
        public byte TimelineTargets { get; set; } = 0x01;

        /// <summary> Show chance time row in edit timeline. </summary> f
        [FieldOrder(70)]
        public byte TimelineChanceTime { get; set; } = 0x01;

        /// <summary> Show technical zone time row in edit timeline. </summary> 
        [FieldOrder(71)]
        public byte TimelineTechnicalZone { get; set; } = 0x01;

        /// <summary> Toggle player 1 module instructions table size. </summary> 
        [FieldOrder(72)]
        public int ShowModulePlayer1sCount { get; set; }

        /// <summary> Toggle player 1 show module instructions. </summary> 
        [FieldOrder(73)]
        [FieldCount(nameof(ShowModulePlayer1sCount))]
        public List<PlayerShowModule> ShowModulePlayer1s { get; set; } = new List<PlayerShowModule>();

        /// <summary> Toggle player 2 show module instructions table size. </summary> 
        [FieldOrder(74)]
        public int ShowModulePlayer2sCount { get; set; }

        /// <summary> Toggle player 2 show module instructions. </summary> 
        [FieldOrder(75)]
        [FieldCount(nameof(ShowModulePlayer2sCount))]
        public List<PlayerShowModule> ShowModulePlayer2s { get; set; } = new List<PlayerShowModule>();

        /// <summary> Toggle player 3 show module instructions table size. </summary> 
        [FieldOrder(76)]
        public int ShowModulePlayer3sCount { get; set; }

        /// <summary> Toggle player 3 show module instructions. </summary> 
        [FieldOrder(77)]
        [FieldCount(nameof(ShowModulePlayer3sCount))]
        public List<PlayerShowModule> ShowModulePlayer3s { get; set; } = new List<PlayerShowModule>();

        /// <summary> Toggle player 1 show accessories instructions table size. </summary> 
        [FieldOrder(78)]
        public int ShowMiscPlayer1sCount { get; set; }

        /// <summary> Toggle player 1 show accessories instructions. </summary> 
        [FieldOrder(79)]
        [FieldCount(nameof(ShowMiscPlayer1sCount))]
        public List<PlayerShowMisc> ShowMiscPlayer1s { get; set; } = new List<PlayerShowMisc>();

        /// <summary> Toggle player 2 show accessories instructions table size. </summary> 
        [FieldOrder(80)]
        public int ShowMiscPlayer2sCount { get; set; }

        /// <summary> Toggle player 2 show accessories instructions. </summary> 
        [FieldOrder(81)]
        [FieldCount(nameof(ShowMiscPlayer2sCount))]
        public List<PlayerShowMisc> ShowMiscPlayer2s { get; set; } = new List<PlayerShowMisc>();

        /// <summary> Toggle player 3 show accessories instructions table size. </summary> 
        [FieldOrder(82)]
        public int ShowMiscPlayer3sCount { get; set; }

        /// <summary> Toggle player 3 show accessories instructions. </summary> 
        [FieldOrder(83)]
        [FieldCount(nameof(ShowMiscPlayer3sCount))]
        public List<PlayerShowMisc> ShowMiscPlayer3s { get; set; } = new List<PlayerShowMisc>();

        /// <summary> Toggle player 1 show shadow instructions table size. </summary> 
        [FieldOrder(84)]
        public int ShowShadowPlayer1sCount { get; set; }

        /// <summary> Toggle player 1 show shadow instructions. </summary> 
        [FieldOrder(85)]
        [FieldCount(nameof(ShowShadowPlayer1sCount))]
        public List<PlayerShowShadow> ShowShadowPlayer1s { get; set; } = new List<PlayerShowShadow>();

        /// <summary> Toggle player 2 show shadow instructions table size. </summary> 
        [FieldOrder(86)]
        public int ShowShadowPlayer2sCount { get; set; }

        /// <summary> Toggle player 2 show shadow instructions. </summary> 
        [FieldOrder(87)]
        [FieldCount(nameof(ShowShadowPlayer2sCount))]
        public List<PlayerShowShadow> ShowShadowPlayer2s { get; set; } = new List<PlayerShowShadow>();

        /// <summary> Toggle player 3 show shadow instructions table size. </summary> 
        [FieldOrder(88)]
        public int ShowShadowPlayer3sCount { get; set; }

        /// <summary> Toggle player 3 show shadow instructions. </summary> 
        [FieldOrder(89)]
        [FieldCount(nameof(ShowShadowPlayer3sCount))]
        public List<PlayerShowShadow> ShowShadowPlayer3s { get; set; } = new List<PlayerShowShadow>();

        /// <summary> Change player 1 position instructions table size. </summary> 
        [FieldOrder(90)]
        public int PlayerPositionPlayer1sCount { get; set; }

        /// <summary> Change player 1 position instructions. </summary> 
        [FieldOrder(91)]
        [FieldCount(nameof(PlayerPositionPlayer1sCount))]
        public List<PlayerPosition> PlayerPositionPlayer1s { get; set; } = new List<PlayerPosition>();

        /// <summary> Change player 2 position instructions table size. </summary> 
        [FieldOrder(92)]
        public int PlayerPositionPlayer2sCount { get; set; }

        /// <summary> Change player 2 position instructions. </summary> 
        [FieldOrder(93)]
        [FieldCount(nameof(PlayerPositionPlayer2sCount))]
        public List<PlayerPosition> PlayerPositionPlayer2s { get; set; } = new List<PlayerPosition>();

        /// <summary> Change player 3 position instructions table size. </summary> 
        [FieldOrder(94)]
        public int PlayerPositionPlayer3sCount { get; set; }

        /// <summary> Change player 3 position instructions. </summary> 
        [FieldOrder(95)]
        [FieldCount(nameof(PlayerPositionPlayer3sCount))]
        public List<PlayerPosition> PlayerPositionPlayer3s { get; set; } = new List<PlayerPosition>();

        /// <summary> Change player 1 motion instructions table size. </summary> 
        [FieldOrder(96)]
        public int PlayerMotionPlayer1sCount { get; set; }

        /// <summary> Change player 1 motion instructions. </summary> 
        [FieldOrder(97)]
        [FieldCount(nameof(PlayerMotionPlayer1sCount))]
        public List<PlayerMotion> PlayerMotionPlayer1s { get; set; } = new List<PlayerMotion>();

        /// <summary> Change player 2 motion instructions table size. </summary> 
        [FieldOrder(98)]
        public int PlayerMotionPlayer2sCount { get; set; }

        /// <summary> Change player 2 motion instructions. </summary> 
        [FieldOrder(99)]
        [FieldCount(nameof(PlayerMotionPlayer2sCount))]
        public List<PlayerMotion> PlayerMotionPlayer2s { get; set; } = new List<PlayerMotion>();

        /// <summary> Change player 3 motion instructions table size. </summary> 
        [FieldOrder(100)]
        public int PlayerMotionPlayer3sCount { get; set; }

        /// <summary> Change player 3 motion instructions. </summary> 
        [FieldOrder(101)]
        [FieldCount(nameof(PlayerMotionPlayer3sCount))]
        public List<PlayerMotion> PlayerMotionPlayer3s { get; set; } = new List<PlayerMotion>();

        /// <summary> Change player 1 facial expression instructions table size. </summary> 
        [FieldOrder(102)]
        public int PlayerExpressionPlayer1sCount { get; set; }

        /// <summary> Change player 1 facial expression instructions. </summary> 
        [FieldOrder(103)]
        [FieldCount(nameof(PlayerExpressionPlayer1sCount))]
        public List<PlayerExpression> PlayerExpressionPlayer1s { get; set; } = new List<PlayerExpression>();

        /// <summary> Change player 2 facial expression instructions table size. </summary> 
        [FieldOrder(104)]
        public int PlayerExpressionPlayer2sCount { get; set; }

        /// <summary> Change player 2 facial expression instructions. </summary> 
        [FieldOrder(105)]
        [FieldCount(nameof(PlayerExpressionPlayer2sCount))]
        public List<PlayerExpression> PlayerExpressionPlayer2s { get; set; } = new List<PlayerExpression>();

        /// <summary> Change player 3 facial expression instructions table size. </summary> 
        [FieldOrder(106)]
        public int PlayerExpressionPlayer3sCount { get; set; }

        /// <summary> Change player 3 facial expression instructions. </summary> 
        [FieldOrder(107)]
        [FieldCount(nameof(PlayerExpressionPlayer3sCount))]
        public List<PlayerExpression> PlayerExpressionPlayer3s { get; set; } = new List<PlayerExpression>();

        // Player Left Hand
        /// <summary> Change player 1 left hand instructions table size. </summary> 
        [FieldOrder(108)]
        public int PlayerLeftHandPlayer1sCount { get; set; }

        /// <summary> Change player 1 left hand instructions. </summary> 
        [FieldOrder(109)]
        [FieldCount(nameof(PlayerLeftHandPlayer1sCount))]
        public List<PlayerHand> PlayerLeftHandPlayer1s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 2 left hand instructions table size. </summary> 
        [FieldOrder(110)]
        public int PlayerLeftHandPlayer2sCount { get; set; }

        /// <summary> Change player 2 left hand instructions. </summary> 
        [FieldOrder(111)]
        [FieldCount(nameof(PlayerLeftHandPlayer2sCount))]
        public List<PlayerHand> PlayerLeftHandPlayer2s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 3 left hand instructions table size. </summary> 
        [FieldOrder(112)]
        public int PlayerLeftHandPlayer3sCount { get; set; }

        /// <summary> Change player 3 left hand instructions. </summary> 
        [FieldOrder(113)]
        [FieldCount(nameof(PlayerLeftHandPlayer3sCount))]
        public List<PlayerHand> PlayerLeftHandPlayer3s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 1 right hand instructions table size. </summary> 
        [FieldOrder(114)]
        public int PlayerRightHandPlayer1sCount { get; set; }

        /// <summary> Change player 1 right hand instructions. </summary> 
        [FieldOrder(115)]
        [FieldCount(nameof(PlayerRightHandPlayer1sCount))]
        public List<PlayerHand> PlayerRightHandPlayer1s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 2 right hand instructions table size. </summary> 
        [FieldOrder(116)]
        public int PlayerRightHandPlayer2sCount { get; set; }

        /// <summary> Change player 2 right hand instructions. </summary> 
        [FieldOrder(117)]
        [FieldCount(nameof(PlayerRightHandPlayer2sCount))]
        public List<PlayerHand> PlayerRightHandPlayer2s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 3 right hand instructions table size. </summary> 
        [FieldOrder(118)]
        public int PlayerRightHandPlayer3sCount { get; set; }

        /// <summary> Change player 3 right hand instructions. </summary> 
        [FieldOrder(119)]
        [FieldCount(nameof(PlayerRightHandPlayer3sCount))]
        public List<PlayerHand> PlayerRightHandPlayer3s { get; set; } = new List<PlayerHand>();

        /// <summary> Change player 1 line of sight instructions table size. </summary> 
        [FieldOrder(120)]
        public int PlayerLineOfSightPlayer1sCount { get; set; }

        /// <summary> Change player 1 line of sight instructions. </summary> 
        [FieldOrder(121)]
        [FieldCount(nameof(PlayerLineOfSightPlayer1sCount))]
        public List<PlayerLineOfSight> PlayerLineOfSightPlayer1s { get; set; } = new List<PlayerLineOfSight>();

        /// <summary> Change player 2 line of sight instructions table size. </summary> 
        [FieldOrder(122)]
        public int PlayerLineOfSightPlayer2sCount { get; set; }

        /// <summary> Change player 2 line of sight instructions. </summary> 
        [FieldOrder(123)]
        [FieldCount(nameof(PlayerLineOfSightPlayer2sCount))]
        public List<PlayerLineOfSight> PlayerLineOfSightPlayer2s { get; set; } = new List<PlayerLineOfSight>();

        /// <summary> Change player 3 line of sight instructions table size. </summary> 
        [FieldOrder(124)]
        public int PlayerLineOfSightPlayer3sCount { get; set; }

        /// <summary> Change player 3 line of sight instructions. </summary> 
        [FieldOrder(125)]
        [FieldCount(nameof(PlayerLineOfSightPlayer3sCount))]
        public List<PlayerLineOfSight> PlayerLineOfSightPlayer3s { get; set; } = new List<PlayerLineOfSight>();

        /// <summary> Player 1 blink instructions table size. </summary> 
        [FieldOrder(126)]
        public int PlayerBlinkPlayer1sCount { get; set; }

        /// <summary> Player 1 blink instructions. </summary> 
        [FieldOrder(127)]
        [FieldCount(nameof(PlayerBlinkPlayer1sCount))]
        public List<PlayerBlink> PlayerBlinkPlayer1s { get; set; } = new List<PlayerBlink>();

        /// <summary> Player 2 blink instructions table size. </summary> 
        [FieldOrder(128)]
        public int PlayerBlinkPlayer2sCount { get; set; }

        /// <summary> Player 2 blink instructions. </summary> 
        [FieldOrder(129)]
        [FieldCount(nameof(PlayerBlinkPlayer2sCount))]
        public List<PlayerBlink> PlayerBlinkPlayer2s { get; set; } = new List<PlayerBlink>();

        /// <summary> Player 3 blink instructions table size. </summary> 
        [FieldOrder(130)]
        public int PlayerBlinkPlayer3sCount { get; set; }

        /// <summary> Player 3 blink instructions. </summary> 
        [FieldOrder(131)]
        [FieldCount(nameof(PlayerBlinkPlayer3sCount))]
        public List<PlayerBlink> PlayerBlinkPlayer3s { get; set; } = new List<PlayerBlink>();

        /// <summary> Player 1 face effect instructions table size. </summary> 
        [FieldOrder(132)]
        public int PlayerFaceEffectPlayer1sCount { get; set; }

        /// <summary> Player 1 face effect instructions. </summary> 
        [FieldOrder(133)]
        [FieldCount(nameof(PlayerFaceEffectPlayer1sCount))]
        public List<PlayerFaceEffect> PlayerFaceEffectPlayer1s { get; set; } = new List<PlayerFaceEffect>();

        /// <summary> Player 2 face effect instructions table size. </summary> 
        [FieldOrder(134)]
        public int PlayerFaceEffectPlayer2sCount { get; set; }

        /// <summary> Player 2 face effect instructions. </summary> 
        [FieldOrder(135)]
        [FieldCount(nameof(PlayerFaceEffectPlayer2sCount))]
        public List<PlayerFaceEffect> PlayerFaceEffectPlayer2s { get; set; } = new List<PlayerFaceEffect>();

        /// <summary> Player 3 face effect instructions table size. </summary> 
        [FieldOrder(136)]
        public int PlayerFaceEffectPlayer3sCount { get; set; }

        /// <summary> Player 3 face effect instructions. </summary> 
        [FieldOrder(137)]
        [FieldCount(nameof(PlayerFaceEffectPlayer3sCount))]
        public List<PlayerFaceEffect> PlayerFaceEffectPlayer3s { get; set; } = new List<PlayerFaceEffect>();

        /// <summary> Player 1 lip-sync. instructions table size. </summary> 
        [FieldOrder(138)]
        public int PlayerLipsyncPlayer1sCount { get; set; }

        /// <summary> Player 1 lip-sync. instructions. </summary> 
        [FieldOrder(139)]
        [FieldCount(nameof(PlayerLipsyncPlayer1sCount))]
        public List<PlayerLipsync> PlayerLipsyncPlayer1s { get; set; } = new List<PlayerLipsync>();

        /// <summary> Player 2 lip-sync. instructions table size. </summary> 
        [FieldOrder(140)]
        public int PlayerLipsyncPlayer2sCount { get; set; }

        /// <summary> Player 2 lip-sync. instructions. </summary> 
        [FieldOrder(141)]
        [FieldCount(nameof(PlayerLipsyncPlayer2sCount))]
        public List<PlayerLipsync> PlayerLipsyncPlayer2s { get; set; } = new List<PlayerLipsync>();

        /// <summary> Player 3 lip-sync. instructions table size. </summary> 
        [FieldOrder(142)]
        public int PlayerLipsyncPlayer3sCount { get; set; }

        /// <summary> Player 3 lip-sync. instructions. </summary> 
        [FieldOrder(143)]
        [FieldCount(nameof(PlayerLipsyncPlayer3sCount))]
        public List<PlayerLipsync> PlayerLipsyncPlayer3s { get; set; } = new List<PlayerLipsync>();

        /// <summary> Change player 1 hand item instructions table size. </summary> 
        [FieldOrder(144)]
        public int PlayerItemPlayer1sCount { get; set; }

        /// <summary> Change player 1 hand item instructions. </summary> 
        [FieldOrder(145)]
        [FieldCount(nameof(PlayerItemPlayer1sCount))]
        public List<PlayerItem> PlayerItemPlayer1s { get; set; } = new List<PlayerItem>();

        /// <summary> Change player 2 hand item instructions table size. </summary> 
        [FieldOrder(146)]
        public int PlayerItemPlayer2sCount { get; set; }

        /// <summary> Change player 2 hand item instructions. </summary> 
        [FieldOrder(147)]
        [FieldCount(nameof(PlayerItemPlayer2sCount))]
        public List<PlayerItem> PlayerItemPlayer2s { get; set; } = new List<PlayerItem>();

        /// <summary> Change player 3 hand item instructions table size. </summary> 
        [FieldOrder(148)]
        public int PlayerItemPlayer3sCount { get; set; }

        /// <summary> Change player 3 hand item instructions. </summary> 
        [FieldOrder(149)]
        [FieldCount(nameof(PlayerItemPlayer3sCount))]
        public List<PlayerItem> PlayerItemPlayer3s { get; set; } = new List<PlayerItem>();

        /// <summary> Edit camera change instructions table size. </summary> 
        [FieldOrder(150)]
        public int EditCamerasCount { get; set; }

        /// <summary> Edit camera change instructions. </summary> 
        [FieldOrder(151)]
        [FieldCount(nameof(EditCamerasCount))]
        public List<EditCamera> EditCameras { get; set; } = new List<EditCamera>();

        /// <summary> Change edit stage instructions table size. </summary> 
        [FieldOrder(152)]
        public int EditStagesCount { get; set; }

        /// <summary> Change edit stage instructions. </summary> 
        [FieldOrder(153)]
        [FieldCount(nameof(EditStagesCount))]
        public List<EditStage> EditStages { get; set; } = new List<EditStage>();

        /// <summary> Change edit lyrics instructions table size. </summary> 
        [FieldOrder(154)]
        public int EditLyricsCount { get; set; }

        /// <summary> Change edit lyrics instructions. </summary> 
        [FieldOrder(155)]
        [FieldCount(nameof(EditLyricsCount))]
        [SerializeWhen(nameof(RegionValue), RegionValue.JPN)]
        public List<EditLyric> EditLyrics { get; set; } = new List<EditLyric>();

        [FieldOrder(156)]
        [FieldCount(nameof(EditLyricsCount))]
        [SerializeWhen(nameof(RegionValue), RegionValue.KYS)]
        public List<KysEditLyric> KysEditLyrics
        {
            get
            {
                List<KysEditLyric> kys = new List<KysEditLyric>(EditLyrics.Count);
                EditLyrics.ForEach(l => kys.Add(new KysEditLyric(l)));
                return kys;
            }
            set
            {
                value.ForEach(l => EditLyrics.Add(l.GetEditLyric()));
            }
        }

        /// <summary> Change edit fade instructions table size. </summary> 
        [FieldOrder(157)]
        public int EditFadesCount { get; set; }

        /// <summary> Change edit fade instructions. </summary> 
        [FieldOrder(158)]
        [FieldCount(nameof(EditFadesCount))]
        public List<EditFade> EditFades { get; set; } = new List<EditFade>();

        /// <summary> Change edit effect instructions table size. </summary> 
        [FieldOrder(159)]
        public int EditEffectsCount { get; set; }

        /// <summary> Change edit effect instructions. </summary> 
        [FieldOrder(160)]
        [FieldCount(nameof(EditEffectsCount))]
        public List<EditEffect> EditEffects { get; set; } = new List<EditEffect>();

        /// <summary> Edit target instructions table size. </summary> 
        [FieldOrder(161)]
        public int EditTargetsCount { get; set; }

        /// <summary> Edit target instructions. </summary> 
        [FieldOrder(162)]
        [FieldCount(nameof(EditTargetsCount))]
        public List<EditTarget> EditTargets { get; set; } = new List<EditTarget>();

        /// <summary> Technical zone instructions table size. </summary> 
        [FieldOrder(163)]
        public int TechnicalZonesCount { get; set; }

        /// <summary> Technical zone instructions. </summary> 
        [FieldOrder(164)]
        [FieldCount(nameof(TechnicalZonesCount))]
        public List<TechZoneArea> TechnicalZones { get; set; } = new List<TechZoneArea>();

        /// <summary> Chance time instructions table size. </summary> 
        [FieldOrder(165)]
        public int ChanceTimesCount { get; set; }

        /// <summary> Chance time instructions. </summary> 
        [FieldOrder(166)]
        [FieldCount(nameof(ChanceTimesCount))]
        public List<ChanceTimeArea> ChanceTimes { get; set; } = new List<ChanceTimeArea>();
        #endregion
        // ----------------------- Constructor ----------------- //
        #region Constructor
        public Edit() { }
        #endregion
        // ----------------------- Methods --------------------- //
        #region Methods
        /// <summary>
        /// Write Edit to file.
        /// </summary>
        /// <param name="editPath"></param>
        /// <param name="header"></param>
        public void Serialize(string editPath, bool header = true)
        {
            var ws = new FileStream(editPath, FileMode.Create);
            var ser = new BinarySerializer() { Endianness = Endianness.Big };
            UpdateCounts();
            ser.Serialize(ws, this);
            ws.Dispose();
            Crc32.UpdateChecksum(editPath);
        }

        /// <summary>
        /// Read Edit from file.
        /// </summary>
        /// <param name="editPath"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        public static Edit Deserialize(string editPath)
        {
            Edit edit = new Edit();
            var ser = new BinarySerializer() { Endianness = Endianness.Big };
            var fs = new FileStream(editPath, FileMode.Open);
            edit = (Edit)ser.Deserialize(fs, typeof(Edit));
            fs.Dispose();
            return edit;
        }

        public static Edit Deserialize(string editPath, Endianness endianness)
        {
            Edit edit = new Edit();
            var ser = new BinarySerializer() { Endianness = endianness };
            var fs = new FileStream(editPath, FileMode.Open);
            edit = (Edit)ser.Deserialize(fs, typeof(Edit));
            fs.Dispose();
            return edit;
        }

        /// <summary>
        /// Update Edit list sizes.
        /// </summary>
        public void UpdateCounts()
        {
            BpmChangesCount = BPMChanges.Count;
            TimeSigChangesCount = TimeSigChanges.Count;
            MarkersCount = Markers.Count;
            TupletAreasCount = TupletAreas.Count;

            ShowModulePlayer1sCount = ShowModulePlayer1s.Count;
            ShowModulePlayer2sCount = ShowModulePlayer2s.Count;
            ShowModulePlayer3sCount = ShowModulePlayer3s.Count;

            ShowMiscPlayer1sCount = ShowMiscPlayer1s.Count;
            ShowMiscPlayer2sCount = ShowMiscPlayer2s.Count;
            ShowMiscPlayer3sCount = ShowMiscPlayer3s.Count;

            ShowShadowPlayer1sCount = ShowShadowPlayer1s.Count;
            ShowShadowPlayer2sCount = ShowShadowPlayer2s.Count;
            ShowShadowPlayer3sCount = ShowShadowPlayer3s.Count;

            PlayerPositionPlayer1sCount = PlayerPositionPlayer1s.Count;
            PlayerPositionPlayer2sCount = PlayerPositionPlayer2s.Count;
            PlayerPositionPlayer3sCount = PlayerPositionPlayer3s.Count;

            PlayerMotionPlayer1sCount = PlayerMotionPlayer1s.Count;
            PlayerMotionPlayer2sCount = PlayerMotionPlayer2s.Count;
            PlayerMotionPlayer3sCount = PlayerMotionPlayer3s.Count;

            PlayerExpressionPlayer1sCount = PlayerExpressionPlayer1s.Count;
            PlayerExpressionPlayer2sCount = PlayerExpressionPlayer2s.Count;
            PlayerExpressionPlayer3sCount = PlayerExpressionPlayer3s.Count;

            PlayerLeftHandPlayer1sCount = PlayerLeftHandPlayer1s.Count;
            PlayerLeftHandPlayer2sCount = PlayerLeftHandPlayer2s.Count;
            PlayerLeftHandPlayer3sCount = PlayerLeftHandPlayer3s.Count;

            PlayerRightHandPlayer1sCount = PlayerRightHandPlayer1s.Count;
            PlayerRightHandPlayer2sCount = PlayerRightHandPlayer2s.Count;
            PlayerRightHandPlayer3sCount = PlayerRightHandPlayer3s.Count;

            PlayerLineOfSightPlayer1sCount = PlayerLineOfSightPlayer1s.Count;
            PlayerLineOfSightPlayer2sCount = PlayerLineOfSightPlayer2s.Count;
            PlayerLineOfSightPlayer3sCount = PlayerLineOfSightPlayer3s.Count;

            PlayerBlinkPlayer1sCount = PlayerBlinkPlayer1s.Count;
            PlayerBlinkPlayer2sCount = PlayerBlinkPlayer2s.Count;
            PlayerBlinkPlayer3sCount = PlayerBlinkPlayer3s.Count;

            PlayerFaceEffectPlayer1sCount = PlayerFaceEffectPlayer1s.Count;
            PlayerFaceEffectPlayer2sCount = PlayerFaceEffectPlayer2s.Count;
            PlayerFaceEffectPlayer3sCount = PlayerFaceEffectPlayer3s.Count;

            PlayerLipsyncPlayer1sCount = PlayerLipsyncPlayer1s.Count;
            PlayerLipsyncPlayer2sCount = PlayerLipsyncPlayer2s.Count;
            PlayerLipsyncPlayer3sCount = PlayerLipsyncPlayer3s.Count;

            PlayerItemPlayer1sCount = PlayerItemPlayer1s.Count;
            PlayerItemPlayer2sCount = PlayerItemPlayer2s.Count;
            PlayerItemPlayer3sCount = PlayerItemPlayer3s.Count;

            EditCamerasCount = EditCameras.Count;

            foreach (var camera in EditCameras)
            {
                camera.KeyPointCount = (byte)camera.CameraKeyPoints.Count;
            }

            EditStagesCount = EditStages.Count;
            EditLyricsCount = EditLyrics.Count;
            EditFadesCount = EditFades.Count;
            EditEffectsCount = EditEffects.Count;
            EditTargetsCount = EditTargets.Count;
            TechnicalZonesCount = TechnicalZones.Count;
            ChanceTimesCount = ChanceTimes.Count;
        }
        #endregion
    }
}